package com.meaningful.thinking.spring.scan_annotations;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.util.HashSet;
import java.util.Set;

/**
 * 在Spring的@Configuration类里通过@Import导入后，它允许你自己编写代码动态地向Spring容器注册Bean定义（BeanDefinition）
 * <p>
 * 当你需要在Spring容器启动时，基于某些条件或者扫描结果，动态生成并注册Bean，而不想写传统的@Bean方法时，这个接口非常适合。
 */
public class MyAnnotationRegistrar implements ImportBeanDefinitionRegistrar {

    private static final Set<String> scannedClasses = new HashSet<>();

    public static Set<String> getScannedClasses() {
        return scannedClasses;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // Spring自带的类路径扫描器，用于扫描指定包下的“候选组件”（即类），并返回它们的Bean定义信息。
        //  可以设置是否启用默认的@Component、@Repository等注解扫描。
        //
        //  可以添加自定义过滤器，比如只扫描标注某个特定注解的类，或者只扫描实现了某接口的类。
        //
        //  返回的是BeanDefinition集合，包含类的完整信息（类名、注解、作用域等）。
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                // 允许接口被扫描为候选组件
                return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent()
                        || super.isCandidateComponent(beanDefinition);
            }
        };
        scanner.addIncludeFilter(new AnnotationTypeFilter(MyAnnotation.class));
        String basePackage = "com.meaningful.thinking.spring.scan_annotations";
        Set<BeanDefinition> candidates = scanner.findCandidateComponents(basePackage);

        for (BeanDefinition bd : candidates) {
            String className = bd.getBeanClassName();
            System.out.println("扫描到带注解的类: " + className);
            scannedClasses.add(className);
        }
    }
}
